#include <string.h>
#include "CryptoUtil.h"

using std::cout;
using std::endl;
using std::string;

string secret_key = "666nwt666";

string CryptoUtil::generate_salt(int length)
{
    string salt{"$6$"};
    for (int i = 0; i < length;)
    {
        int k = rand() % 127;
        if ((k >= 46 && k <= 57) || (k >= 65 && k <= 90) || (k >= 97 && k <= 122))
        {
            char c = k;
            salt.push_back(c);
            ++i;
        }
    }
    salt.push_back('$');
    return salt;
}

string CryptoUtil::hash(User &user, const EVP_MD *evp_md)
{
    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
    unsigned char hash[EVP_MAX_MD_SIZE];
    unsigned int hash_len;

    EVP_DigestInit_ex(ctx, evp_md, NULL);
    string Pwd = user.salt + user.password;
    EVP_DigestUpdate(ctx, Pwd.c_str(), Pwd.size());
    EVP_DigestFinal_ex(ctx, hash, &hash_len);

    string result{};
    for (unsigned int i = 0; i < hash_len; i++)
    {
        char temp[3] = {0};
        sprintf(temp, "%02x", hash[i]);
        result += temp;
    }
#ifdef DEBUG
    cout << "[DEBUG]" << "getHash: " << result << endl;
#endif
    EVP_MD_CTX_free(ctx);
    return result;
}

string CryptoUtil::hashFile(string content, const EVP_MD *evp_md)
{
    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
    unsigned char hash[EVP_MAX_MD_SIZE];
    unsigned int hash_len;

    EVP_DigestInit_ex(ctx, evp_md, NULL);
    EVP_DigestUpdate(ctx, content.c_str(), content.size());
    EVP_DigestFinal_ex(ctx, hash, &hash_len);

    string result{};
    for (unsigned int i = 0; i < hash_len; i++)
    {
        char temp[3] = {0};
        sprintf(temp, "%02x", hash[i]);
        result += temp;
    }
#ifdef DEBUG
    cout << "[DEBUG]" << "getFileHash: " << result << endl;
#endif
    EVP_MD_CTX_free(ctx);
    return result;
}

string CryptoUtil::generate_token(const User &user, jwt_alg_t jwt_alg)
{
    jwt_t *jwt;
    jwt_new(&jwt); // 创建 JWT

    // 设置算法为 HS256
    jwt_set_alg(jwt, jwt_alg, (unsigned char *)secret_key.data(), secret_key.size());

    // 设置载荷(Payload): 用户自定义数据
    jwt_add_grant(jwt, "sub", "login");
    jwt_add_grant(jwt, "username", user.username.data()); // 用户ID
    jwt_add_grant_int(jwt, "expire", time(NULL) + 1800);  // 过期时间 (半小时)

    string token = jwt_encode_str(jwt); // token长度是不确定的，100-300字节

    // 释放资源
    jwt_free(jwt);
    return token;
}

bool CryptoUtil::varify_token(string &token, User &user)
{
    jwt_t *jwt;
    int err = jwt_decode(&jwt, token.data(), (unsigned char *)secret_key.data(), secret_key.size());
    if (err)
    {
#ifdef DEBUG
        cout << "Invalid JWT!" << endl;
#endif
        return false;
    }

    if (jwt_get_grant_int(jwt, "expire") < time(NULL))
    {
        jwt_free(jwt);
#ifdef DEBUG
        cout << "超时" << endl;
#endif
        return false;
    }
    if (strcmp(jwt_get_grant(jwt, "sub"), "login") != 0)
    {
        jwt_free(jwt);
#ifdef DEBUG
        cout << "验证出错" << endl;
#endif
        return false;
    }
    // 获取 Payload
    user.username = jwt_get_grant(jwt, "username");

    jwt_free(jwt);
    return true;
}